#pragma once

#include <iostream>
#include <string>
#include <unordered_map>
#include <cassert>
#include "Socket.hpp"
#include "Connection.hpp"
#include "Epoll.hpp"
#include "Log copy.hpp"
using namespace LogModule;

static const int EPOLL_TIME = -1;
static const int EPOLL_SIZE = 1024;

class TcpServer
{
    using Epoll = EpollModule::Epoll;
    void LoopOnce()
    {
        int n = _epoll.WaitEpollEvent(_event);
        if (n <= 0)
            return;
        if (n > 0)
        {
            for (int i = 0; i < n; i++)
            {
                uint32_t evt = _event[i].events;
                int socket = _event[i].data.fd;
                logger(LogLevel::DEBUG, __FILE__, __LINE__) << "Socket" << socket << "has event!";
                if (evt & EPOLLERR)
                {
                    logger(LogLevel::DEBUG, __FILE__, __LINE__) << "EPOLLERR:" << strerror(errno);
                    evt |= (EPOLLIN | EPOLLOUT);
                }
                    
                if (evt & EPOLLHUP)
                {
                    logger(LogLevel::DEBUG, __FILE__, __LINE__) << "EPOLLHUP:" << strerror(errno);
                     evt |= (EPOLLIN | EPOLLOUT);
                }
                   
                if (evt & EPOLLIN)
                {
                    // 读事件到来
                    if (ExistConnection(socket) && _conn[socket]->_reader)
                    {
                        _conn[socket]->_reader(_conn[socket]);
                    }
                }
                if (evt & EPOLLOUT)
                {
                    // 写事件到来
                    if (ExistConnection(socket) && _conn[socket]->_writer)
                    {
                        _conn[socket]->_writer(_conn[socket]);
                    }
                }
            }
        }
    }

public:
    TcpServer(int waittime = -1) : _wait_time(waittime)
    {
    }

    void EnableReadWrite(int socket, bool readable, bool writebale)
    {
        if (!ExistConnection(socket))
            return;
        // 设置红黑树里面的读写
        uint32_t evt = (readable ? EPOLLIN : 0) | (writebale ? EPOLLOUT : 0) | EPOLLET;
        // 1、写道连接中去
        _conn[socket]->SetEvent(evt);
        // 2、写道事件中去
        _epoll.ModEpollEvent(socket, evt);
    }

    bool ExistConnection(int socket)
    {
        // for (auto &x : _conn)
        //     std::cout << x.first << " ";
        // std::cout << std::endl;
        // // std::cout << _conn.size() << std::endl;
        // std::cout << "------------------" << std::endl;
        // std::cout << _conn.count(socket) << std::endl;
        // std::cout << "------------------" << std::endl;
        return _conn.count(socket);
    }

    void AddConnction(Connection *conn)
    {
        logger(LogLevel::DEBUG, __FILE__, __LINE__) << "AddConnction";
        assert(conn);
        // 0、不要重复添加。
        std::cout << conn->GetSocket() << std::endl;
        if (ExistConnection(conn->GetSocket()))
        {
            return;
        }
        logger(LogLevel::DEBUG, __FILE__, __LINE__) << "--------------1---------------";
        // 1、写透到内核
        bool ret = _epoll.AddEpollEvent(conn->GetSocket(), conn->GetEvent());
        if(!ret) return;
        logger(LogLevel::DEBUG, __FILE__, __LINE__) << "----------------2---------------";
        _epoll.DebugFdList();
        // 2、添加到哈希表里面
        _conn.insert(std::make_pair(conn->GetSocket(), conn));
    }

    void RemoveConnction(int socket)
    {
        if (!ExistConnection(socket))
            return;
        // 去epoll模型删除红黑树节点
        _epoll.DelEpollEvent(socket);
        // 删除connction中事件关心
        _conn[socket]->SetEvent(0);
        // 删除hash表对应的内容
        _conn.erase(socket);
    }

    void EventDispatcher()
    {
        while (true)
        {
            LoopOnce();
        }
    }

private:
    Epoll _epoll;
    std::unordered_map<int, Connection *> _conn;
    int _wait_time;
    epoll_event _event[EPOLL_SIZE];
};